# Copyright (C) Infiscape Corporation 2006
import sys, os, os.path, time, traceback, math
pj = os.path.join

from PyQt4 import QtGui, QtCore, QtOpenGL

import osg2

import viewer_base
import lucid.core
from lucid.view.our_dock_widget import OurDockWidget
from pydispatch import dispatcher

class Viewer(QtGui.QMainWindow, viewer_base.Ui_MainWindow):
   """ The MainWindow for the application.
       This holds:
          - Main menu
          - Active dock widgets
          - Scene views
   """
   def __init__(self, parent = None):
      """ Initialize the core window.
          This method is not called until the environment and plugin manager have
          been setup.
      """
      QtGui.QMainWindow.__init__(self, parent)
      self.setupUi(self)
      self.setupExtraMenus()
      
      self.mActiveDocks = []  # List of active dock widgets
      self.mSceneViews = {}   # Map: Scene object --> Scene view widget      
      
      # Register callbacks
      #dispatcher.connect(self.onSceneAdd, lucid.core.signal.SceneAdded)
      dispatcher.connect(self.onSceneActivated, lucid.core.signal.ActiveSceneChanged)
      dispatcher.connect(self.onSaveState, lucid.core.signal.SaveStateForExit)
      
      # Load settings from setting file
      self.loadSettings()


   def setupUi(self, widget):
      viewer_base.Ui_MainWindow.setupUi(self, widget)

      # Replace central widget
      self.workspace = QtGui.QWorkspace()
      self.setCentralWidget(self.workspace)   
      
      # Setup action callbacks
      self.connect(self.actionNew, QtCore.SIGNAL("triggered()"), self.onNew)
      self.connect(self.actionOpen, QtCore.SIGNAL("triggered()"), self.onOpen)
      self.connect(self.actionSave, QtCore.SIGNAL("triggered()"), self.onSave)
      self.connect(self.actionSave_As, QtCore.SIGNAL("triggered()"), self.onSaveAs)
      self.connect(self.actionClose, QtCore.SIGNAL("triggered()"), self.onClose)
      self.connect(self.actionQuit, QtCore.SIGNAL("triggered()"), self.onQuit)
      self.connect(self.actionNewViewDock, QtCore.SIGNAL("triggered()"), self.onNewViewDock)
      self.connect(self.actionReloadPlugins, QtCore.SIGNAL("triggered()"), self.onReloadPlugins)
      self.connect(self.workspace, QtCore.SIGNAL("windowActivated(QWidget*)"), 
                   self.onWindowActivated)
      
      self.connect(self.actionLightDecoration, QtCore.SIGNAL("toggled(bool)"), 
                   self.onLightDecorToggled)
      self.connect(self.actionToggleHeadlight, QtCore.SIGNAL("toggled(bool)"), 
                   self.onHeadlightToggled)
      self.connect(self.actionShowAll, QtCore.SIGNAL("triggered()"), self.onShowAll)
   
   def setupExtraMenus(self):
      # Add plugin menus here.
      pass
   
   # ----------- ACTION CALLBACKS -------------------- #
   def onNew(self):
      lucid.core.Environment().addEmptyScene()      
   
   def onOpen(self):
      fileName = QtGui.QFileDialog.getOpenFileName(self,
                       "Open File...",
                        os.getcwd(),
                        "OSB Files (*.osb);;All Files (*)")
      if not fileName.isEmpty():
         lucid.core.Environment().openFile(str(fileName))
   
   def onSave(self):
      cur_scene = lucid.core.Environment().activeScene
      if "" == cur_scene.mFileName:
         self.onSaveAs()
      else:
         cur_scene.save()

   def onSaveAs(self):      
      fileName = QtGui.QFileDialog.getSaveFileName(self,
                       "Save file as...",
                        os.getcwd(),
                       "All Files (*);;OSB Files (*.osb)")
      if not fileName.isEmpty():
         cur_scene = lucid.core.Environment().activeScene
         cur_scene.mFileName = str(fileName)
         cur_scene.save()

   def onClose(self):
      pass
   
   def onQuit(self):
      self.close()
   
   def onReloadPlugins(self):
      print "Reloading plugins."
      env = lucid.core.Environment()
      env.pluginManager.reload()
   
   def onNewViewDock(self):
      new_dock = OurDockWidget(parent=self)
      self.connect(new_dock, QtCore.SIGNAL("pyDockableClosing"), self.dockableClosed)
      self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, new_dock)
      new_dock.setFloating(True)
      self.mActiveDocks.append(new_dock)
   
   def onShowAll(self):
      print "onShowAll called."
      cur_scene = lucid.core.Environment().activeScene
      cur_scene_view = self.mSceneViews.get(cur_scene, None)
      if cur_scene_view:
         cur_scene_view.showAll()
   
   def onLightDecorToggled(self, val):
      print "onLightDecorToggled called with: ", val
      cur_scene = lucid.core.Environment().activeScene
      
      if True == val:
         cur_scene.mLightDecorator.decorate()
      elif False == val:
         cur_scene.mLightDecorator.undecorate()

   def onHeadlightToggled(self, val):
      print "toggle headlight called."
      cur_scene = lucid.core.Environment().activeScene
      cur_scene_view = self.mSceneViews.get(cur_scene, None)
      if cur_scene_view:
         cur_scene_view.getManager().setHeadlight(val)

   def dockableClosed(self, dock):
      if dock in self.mActiveDocks:
         self.mActiveDocks.remove(dock)
   
   def closeEvent(self, event):
      """ Intercept the close event so we can save settings. """
      env = lucid.core.Environment()
      env.saveSettings()
      event.accept()
      #event.ignore()

   def onSaveState(self):
      env = lucid.core.Environment()
      settings_dict = env.settings.settings
      
      dock_states = []
      for d in self.mActiveDocks:
         dock_states.append(d.saveState())
      settings_dict["viewer.dock_states"] = dock_states      

      win_state = str(self.saveState())
      settings_dict["viewer.win_state"] = win_state
      
      win_size = self.size()
      win_pos = self.pos()
      settings_dict["viewer.size"] = (win_size.width(), win_size.height())
      settings_dict["viewer.pos"] = (win_pos.x(), win_pos.y())
      

   def loadSettings(self):
      env = lucid.core.Environment()
      settings_dict = env.settings.settings

      dock_states = settings_dict.get("viewer.dock_states",None)
      if dock_states:
         for d in dock_states:
            self.onNewViewDock()
            new_dock = self.mActiveDocks[-1]
            new_dock.loadState(d)
      
      win_state = settings_dict.get("viewer.win_state",None)
      if win_state:
         self.restoreState(QtCore.QByteArray(win_state))
      
      win_size = settings_dict.get("viewer.size",None)
      if win_size:
         self.resize(QtCore.QSize(win_size[0], win_size[1]))
      win_pos = settings_dict.get("viewer.pos",None)
      if win_pos:
         self.move(win_pos[0], win_pos[1])

   
   # --------------- SCENE VIEW WIDGETS ------------ #
   def viewScene(self, scene):
      """ Scene has be set and we need to update the view to show it.
          This lazy creates viewers for the scene.
      """
      if self.mSceneViews.has_key(scene):
         view_win = self.mSceneViews[scene]
         if self.workspace.activeWindow() != view_win:
            self.mSceneViews[scene].show()         
      else:
         view_win = lucid.core.SceneViewWidget(scene)
         self.mSceneViews[scene] = view_win         
         self.workspace.addWindow(view_win)
         view_win.show()

   def onWindowActivated(self, window):
      """ Qt slot called with workspace.windowActivated is emitted."""
      # Find the scene to activate
      # Tell environment to activiate it, triggers callbacks.
      print "windowactivated: ", window
      if not window:
         return
      for (scene, view_win) in self.mSceneViews.iteritems():
         if view_win == window:
            lucid.core.Environment().activeScene = scene
            return
      
      assert False, "Viewer: Could not find the window activated."

   #def onSceneAdd(self):
   #   env = lucid.core.Environment()      
   #   self.viewScene(env.activeScene)      
   
   def onSceneActivated(self):
      env = lucid.core.Environment()      
      self.viewScene(env.activeScene)

   def __tr(self,s,c = None):
      return qApp.translate("MainWindow",s,c)
   

